using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Domain.Interfaces.Repositories;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    public class GrowthGoalRepository : Repository<GrowthGoal>, IGrowthGoalRepository
    {
        public GrowthGoalRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthGoal>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(g => g.UserId == userId)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoal>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(g => g.Category == category)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoal>> GetByStatusAsync(string status)
        {
            return await _dbSet
                .Where(g => g.Status == status)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoal>> GetByUserIdAndCategoryAsync(Guid userId, string category)
        {
            return await _dbSet
                .Where(g => g.UserId == userId && g.Category == category)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }
    }

    public class GrowthGoalTaskRepository : Repository<GrowthGoalTask>, IGrowthGoalTaskRepository
    {
        public GrowthGoalTaskRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthGoalTask>> GetByGoalIdAsync(Guid goalId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalId == goalId)
                .OrderBy(g => g.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoalTask>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Include(g => g.GrowthGoal)
                .Where(g => g.GrowthGoal.UserId == userId)
                .OrderBy(g => g.GrowthGoalId)
                .ThenBy(g => g.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoalTask>> GetByStatusAsync(string status)
        {
            return await _dbSet
                .Where(g => g.Status == status)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoalTask>> GetByGoalIdOrderByOrderAsync(Guid goalId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalId == goalId)
                .OrderBy(g => g.Order)
                .ToListAsync();
        }
    }

    public class GrowthGoalRecordRepository : Repository<GrowthGoalRecord>, IGrowthGoalRecordRepository
    {
        public GrowthGoalRecordRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthGoalRecord>> GetByGoalIdAsync(Guid goalId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalId == goalId)
                .OrderByDescending(g => g.RecordDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoalRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Include(g => g.GrowthGoal)
                .Where(g => g.GrowthGoal.UserId == userId && g.RecordDate >= startDate && g.RecordDate <= endDate)
                .OrderByDescending(g => g.RecordDate)
                .ToListAsync();
        }

        public async Task<GrowthGoalRecord> GetLatestByGoalIdAsync(Guid goalId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalId == goalId)
                .OrderByDescending(g => g.RecordDate)
                .FirstOrDefaultAsync();
        }
    }

    public class GrowthGoalTaskRecordRepository : Repository<GrowthGoalTaskRecord>, IGrowthGoalTaskRecordRepository
    {
        public GrowthGoalTaskRecordRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthGoalTaskRecord>> GetByTaskIdAsync(Guid taskId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalTaskId == taskId)
                .OrderByDescending(g => g.RecordDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthGoalTaskRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Include(g => g.GrowthGoalTask)
                .ThenInclude(g => g.GrowthGoal)
                .Where(g => g.GrowthGoalTask.GrowthGoal.UserId == userId && g.RecordDate >= startDate && g.RecordDate <= endDate)
                .OrderByDescending(g => g.RecordDate)
                .ToListAsync();
        }

        public async Task<GrowthGoalTaskRecord> GetLatestByTaskIdAsync(Guid taskId)
        {
            return await _dbSet
                .Where(g => g.GrowthGoalTaskId == taskId)
                .OrderByDescending(g => g.RecordDate)
                .FirstOrDefaultAsync();
        }
    }

    public class GrowthArchiveRepository : Repository<GrowthArchive>, IGrowthArchiveRepository
    {
        public GrowthArchiveRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthArchive>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(g => g.UserId == userId)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthArchive>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(g => g.Category == category)
                .OrderBy(g => g.Title)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthArchive>> GetByUserIdAndCategoryAsync(Guid userId, string category)
        {
            return await _dbSet
                .Where(g => g.UserId == userId && g.Category == category)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }

        public async Task<GrowthArchive> GetLatestByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(g => g.UserId == userId)
                .OrderByDescending(g => g.CreatedTime)
                .FirstOrDefaultAsync();
        }
    }

    public class GrowthArchiveItemRepository : Repository<GrowthArchiveItem>, IGrowthArchiveItemRepository
    {
        public GrowthArchiveItemRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthArchiveItem>> GetByArchiveIdAsync(Guid archiveId)
        {
            return await _dbSet
                .Where(g => g.GrowthArchiveId == archiveId)
                .OrderBy(g => g.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthArchiveItem>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Include(g => g.GrowthArchive)
                .Where(g => g.GrowthArchive.UserId == userId)
                .OrderByDescending(g => g.GrowthArchive.CreatedTime)
                .ThenBy(g => g.Order)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthArchiveItem>> GetByTypeAsync(string type)
        {
            return await _dbSet
                .Where(g => g.Type == type)
                .OrderBy(g => g.Title)
                .ToListAsync();
        }
    }

    public class EmotionDiaryRepository : Repository<EmotionDiary>, IEmotionDiaryRepository
    {
        public EmotionDiaryRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<EmotionDiary>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(e => e.UserId == userId)
                .OrderByDescending(e => e.DiaryDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<EmotionDiary>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(e => e.UserId == userId && e.DiaryDate >= startDate && e.DiaryDate <= endDate)
                .OrderByDescending(e => e.DiaryDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<EmotionDiary>> GetByEmotionTypeAsync(string emotionType)
        {
            return await _dbSet
                .Where(e => e.EmotionType == emotionType)
                .OrderByDescending(e => e.DiaryDate)
                .ToListAsync();
        }

        public async Task<EmotionDiary> GetLatestByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(e => e.UserId == userId)
                .OrderByDescending(e => e.DiaryDate)
                .FirstOrDefaultAsync();
        }
    }

    public class EmotionDiaryCommentRepository : Repository<EmotionDiaryComment>, IEmotionDiaryCommentRepository
    {
        public EmotionDiaryCommentRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<EmotionDiaryComment>> GetByDiaryIdAsync(Guid diaryId)
        {
            return await _dbSet
                .Where(e => e.EmotionDiaryId == diaryId)
                .OrderBy(e => e.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<EmotionDiaryComment>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(e => e.UserId == userId)
                .OrderByDescending(e => e.CreatedTime)
                .ToListAsync();
        }
    }

    public class EmotionDiaryLikeRepository : Repository<EmotionDiaryLike>, IEmotionDiaryLikeRepository
    {
        public EmotionDiaryLikeRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<EmotionDiaryLike>> GetByDiaryIdAsync(Guid diaryId)
        {
            return await _dbSet
                .Where(e => e.EmotionDiaryId == diaryId)
                .OrderByDescending(e => e.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<EmotionDiaryLike>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(e => e.UserId == userId)
                .OrderByDescending(e => e.CreatedTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserLikedAsync(Guid userId, Guid diaryId)
        {
            return await _dbSet
                .AnyAsync(e => e.UserId == userId && e.EmotionDiaryId == diaryId);
        }
    }

    public class GrowthCourseRepository : Repository<GrowthCourse>, IGrowthCourseRepository
    {
        public GrowthCourseRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthCourse>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(g => g.Category == category)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthCourse>> GetByDifficultyAsync(string difficulty)
        {
            return await _dbSet
                .Where(g => g.Difficulty == difficulty)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthCourse>> GetByInstructorAsync(string instructor)
        {
            return await _dbSet
                .Where(g => g.Instructor == instructor)
                .OrderBy(g => g.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthCourse>> SearchByNameAsync(string keyword)
        {
            return await _dbSet
                .Where(g => g.Name.Contains(keyword))
                .OrderBy(g => g.Name)
                .ToListAsync();
        }
    }

    public class GrowthCourseLessonRepository : Repository<GrowthCourseLesson>, IGrowthCourseLessonRepository
    {
        public GrowthCourseLessonRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthCourseLesson>> GetByCourseIdAsync(Guid courseId)
        {
            return await _dbSet
                .Where(g => g.GrowthCourseId == courseId)
                .OrderBy(g => g.LessonOrder)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthCourseLesson>> GetByCourseIdOrderByOrderAsync(Guid courseId)
        {
            return await _dbSet
                .Where(g => g.GrowthCourseId == courseId)
                .OrderBy(g => g.LessonOrder)
                .ToListAsync();
        }
    }

    public class UserGrowthCourseRepository : Repository<UserGrowthCourse>, IUserGrowthCourseRepository
    {
        public UserGrowthCourseRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserGrowthCourse>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.EnrollTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserGrowthCourse>> GetByCourseIdAsync(Guid courseId)
        {
            return await _dbSet
                .Where(u => u.GrowthCourseId == courseId)
                .OrderByDescending(u => u.EnrollTime)
                .ToListAsync();
        }

        public async Task<bool> IsUserCourseExistsAsync(Guid userId, Guid courseId)
        {
            return await _dbSet
                .AnyAsync(u => u.UserId == userId && u.GrowthCourseId == courseId);
        }
    }

    public class UserGrowthCourseProgressRepository : Repository<UserGrowthCourseProgress>, IUserGrowthCourseProgressRepository
    {
        public UserGrowthCourseProgressRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserGrowthCourseProgress>> GetByUserIdAndCourseIdAsync(Guid userId, Guid courseId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId && u.GrowthCourseId == courseId)
                .OrderBy(u => u.CompletedTime)
                .ToListAsync();
        }

        public async Task<UserGrowthCourseProgress> GetByUserIdAndLessonIdAsync(Guid userId, Guid lessonId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId && u.GrowthCourseLessonId == lessonId)
                .FirstOrDefaultAsync();
        }

        public async Task<IEnumerable<UserGrowthCourseProgress>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.CompletedTime)
                .ToListAsync();
        }
    }

    public class GrowthCourseReviewRepository : Repository<GrowthCourseReview>, IGrowthCourseReviewRepository
    {
        public GrowthCourseReviewRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<GrowthCourseReview>> GetByCourseIdAsync(Guid courseId)
        {
            return await _dbSet
                .Where(g => g.GrowthCourseId == courseId)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<GrowthCourseReview>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(g => g.UserId == userId)
                .OrderByDescending(g => g.CreatedTime)
                .ToListAsync();
        }

        public async Task<double> GetAverageRatingByCourseIdAsync(Guid courseId)
        {
            return await _dbSet
                .Where(g => g.GrowthCourseId == courseId)
                .AverageAsync(g => g.Rating);
        }
    }
}